package uy.org.softtech.cssuite.web.controladores;

import static org.springframework.security.core.context.SecurityContextHolder.getContext;
import static org.springframework.util.Assert.notNull;
import static org.springframework.web.servlet.support.RequestContextUtils.getLocale;
import java.util.Locale;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import uy.org.softtech.cssuite.core.Controlador;
import uy.org.softtech.cssuite.servicios.ServiciosTareas;
import uy.org.softtech.cssuite.servicios.ServiciosUsuarios;

/**
 * Controlador encargado de manejar el acceso a la aplicación.
 * 
 * @author fabian.lobo
 */
@Configuration
@Controller("controlador-seguridad")
@ManagedResource(
	objectName = "cssuite:type=Controlador,name=ControladorSeguridad", 
	description = "Controlador encargado de manejar el acceso a la aplicación.",
	log = true, logFile = "jmx.log", currencyTimeLimit = 15,
	persistPolicy = "OnUpdate", persistPeriod = 200
)
public class ControladorSeguridad extends Controlador {

	private Logger log = Logger.getLogger(getClass());
	
	// Servicios
	@Resource(name = "servicios-usuarios" )
	private ServiciosUsuarios serviciosUsuarios;
	
	@Resource(name = "servicios-tareas" )
	private ServiciosTareas serviciosTareas;
	
	/**
	 * Método para verificar que todos los parámetros han sido seteados correctamente.
	 * 
	 * @author fabian.lobo
	 */
	@PostConstruct
	public void inicializacion(){
		super.inicializacion();
		
		notNull(serviciosUsuarios(), "La propiedad [serviciosUsuarios] de [" + getClass().getName() + "] no ha sido establecida.");
		notNull(serviciosTareas(), "La propiedad [serviciosTareas] de [" + getClass().getName() + "] no ha sido establecida.");
		
		log.info("Controlador encargado de manejar el acceso a la aplicación ha sido inicializado.");
	}
	
	/* 
	 * ---------------------------------------
	 * ------------    ENTRADA   -------------
	 * ---------------------------------------
	 */
	/**
	 * Retorna la página de entrada.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.GET, value = "entrar.do")
	@Secured(value = {"IS_AUTHENTICATED_ANONYMOUSLY"})
	public ModelAndView entrar(HttpServletRequest request){
		Locale locale = getLocale(request);
		getContext().setAuthentication(null);
		
		return new ModelAndView("redirect:entrar.do?lang=" + locale.getLanguage());
	}
	
	/**
	 * Retorna la página de entrada (para un lenguaje específico).
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.GET, value = "entrar.do", params = "lang")
	@Secured(value = {"IS_AUTHENTICATED_ANONYMOUSLY"})
	public String entrar(@RequestParam("lang") String lenguaje) {
		getContext().setAuthentication(null);
		
		return "entrar";
	}
	
	/* 
	 * ---------------------------------------
	 * ----------  INACCESIBLE   -------------
	 * ---------------------------------------
	 */
	/**
	 * Retorno a un código de estado HTTP 403.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, value = "inaccesible.do")
	@Secured(value = {"IS_AUTHENTICATED_ANONYMOUSLY"})
	public ModelAndView inaccesible(HttpServletRequest request){
		Locale locale = getLocale(request);
		
		String mensaje = fuenteMensajes().getMessage("mensaje.accessRestringido", null, "Ud. no tiene acceso para acceder al recurso solicitado. Por favor, contacte al administrador del sistema.", locale);
		ModelAndView respuesta = new ModelAndView();
		if(getContext().getAuthentication() == null) {		//Usuario no autenticado -> Muestro página de login
			respuesta.setViewName("entrar");
		} else {											//Usuario autenticado -> Muestro página de inicio
			respuesta.setViewName("inicio");
		}
		mostrarMensajeError(respuesta, mensaje, true, "inicio.do");
		
		return respuesta;
	}
	
	/* 
	 * ---------------------------------------
	 * ----------     ERROR      -------------
	 * ---------------------------------------
	 */
	/**
	 * Retorno a un código de estado HTTP 500.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, value = "error.do")
	@Secured(value = {"IS_AUTHENTICATED_ANONYMOUSLY"})
	public ModelAndView error(HttpServletRequest request){
		Locale locale = getLocale(request);
		
		String mensaje = fuenteMensajes().getMessage("mensaje.errorGeneral", null, "Ha ocurrido un error no esperado. Por favor, contacte al administrador del sistema.", locale);
		ModelAndView respuesta = new ModelAndView();
		if(getContext().getAuthentication() == null) {		//Usuario no autenticado -> Muestro página de login
			respuesta.setViewName("entrar");
		} else {											//Usuario autenticado -> Muestro página de inicio
			respuesta.setViewName("inicio");
		}
		mostrarMensajeError(respuesta, mensaje, true, "inicio.do");
		
		return respuesta;
	}
	
	/* 
	 * ---------------------------------------
	 * ---------   EXPIRACION    -------------
	 * ---------------------------------------
	 */
	/**
	 * Retorno la página cuando un token ha expirado
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.GET, value = "expirado.do")
	@Secured(value = {"IS_AUTHENTICATED_ANONYMOUSLY"})
	public ModelAndView expirado(HttpServletRequest request){
		Locale locale = getLocale(request);
		
		String mensaje = fuenteMensajes().getMessage("mensaje.paginaExpirada", null, "La página solicitada no está vigente.", locale);
		ModelAndView respuesta = new ModelAndView("entrar");
		mostrarMensajeError(respuesta, mensaje, true, "entrar.do");
		return respuesta;
	}
	
	/* 
	 * ---------------------------------------
	 * --------  PAGINA PRINCIPAL   ----------
	 * ---------------------------------------
	 */
	
	/**
	 * Redirecciona a la página principal.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.GET, value = "inicio.do")
	@Secured(value = {"ROLE_AUTENTICADO"})
	public String inicio() {
		if(getContext().getAuthentication() == null) {
			return "redirect:entrar.do";
		}
		return "inicio";
	}
	
	/*
	 *  GETTERS
	 */
	public ServiciosUsuarios serviciosUsuarios() {
		return serviciosUsuarios;
	}
	public ServiciosTareas serviciosTareas() {
		return serviciosTareas;
	}
	
}
